from flask_restful import Resource,reqparse,inputs
from flask import g
from pymysql import IntegrityError

from toutiao.utils.decorators import Loginrequired
from models.news import Comment,CommentLiking
from toutiao import db
from .constants import DEFAULT_COMMENT_PER_PAGE_MIN,DEFAULT_COMMENT_PER_PAGE_MAX
from . import constants
#发布评论
class CommentResource(Resource):
    method_decorators = {'post':[Loginrequired]}

    def post(self):
        '''
        发布评论：
        接收数据，那个用户，评论哪篇文章
        验证数据
        评论保存到数据库(评论本应通过敏感字过滤，此处未实现此功能)
        返回相应
        :return:
        '''
        user_id = g.user_id
        parse = reqparse.RequestParser()
        parse.add_argument('target', required=True)
        parse.add_argument('content', required=True)
        parse.add_argument('art_id', type=int, required=False, location='json')
        args = parse.parse_args()

        comment = Comment()
        comment.article_id = args.get('target')
        comment.content = args.get('content')
        comment.user_id = user_id

        #如果有回复id，表示回复评论
        art_id=args.art_id
        if art_id:
            comment.article_id=art_id
            comment.parent_id=args.target
            #调用统计回复评论的数据，加一
            from cache.statistic import CommentReplyCountStorage
            CommentReplyCountStorage.incr(args.get('target'))
        #没有，说明为评论，以下代码无需改动，teacher版本已经写好，此为own版本
        try:
            db.session.add(comment)
            db.session.commit()
        except Exception:
            return {}

        return {
            "com_id": comment.id,
            "target": comment.article_id,
            'art_id':art_id
        },201

    #获取评论列表,手机查看10条评论上滑，滑到最下并不会提示点击某一页，而是继续加载10条，此时用到偏移量
    def get(self):

        """ 接收数据,前端通过查询字符串发送以下４个数据/comments?source=x&offset=xxx&limit=xxx
            type(query)	    str	必传	评论类型，a表示文章评论 c表示回复评论
            source(query)	int	必传	文章id或者评论id     int或者inputs.positive
            offset(query)	int	否	获取评论数据的偏移量(时间戳)
            limit(query)	int	否	单页返回的记录条数，最大不超过50，默认为10(常量单独写在constants)
        """
        parser = reqparse.RequestParser()
        parser.add_argument('type',location='args',type=str,required=True)
        parser.add_argument('source',location='args',type=int,required=True)
        parser.add_argument('offset',location='args',type=inputs.positive)
        parser.add_argument('limit',location='args',type=inputs.int_range(DEFAULT_COMMENT_PER_PAGE_MIN,DEFAULT_COMMENT_PER_PAGE_MAX,'limit'))
        args = parser.parse_args()
        #判断是否传来limit，传来用前端传来的值，没有传来用一个常量10
        limit = args.limit if args.limit is not None else DEFAULT_COMMENT_PER_PAGE_MIN
        offset = args.get('offset',constants.DEFAULT_COMMENT_PER_PAGE_MIN)
        source = args.get('source')
        type = args.get('type')
        #以下为使用缓存实现
        if type == 'a':
            from cache.comment import ArticleCommentCache,CommentCache
            total_count, end_id, last_id, page_comments_ids = ArticleCommentCache(source).get_page(offset, limit)
            #page_comments_ids是所有评论id列表，page_comments是所有评论详情列表
            page_comments = CommentCache.get_list(page_comments_ids)

        else:
            from cache.comment import CommentsReplyCache, CommentCache
            total_count, end_id, last_id, page_comments_ids = CommentsReplyCache(source).get_page(offset, limit)
            page_comments = CommentCache.get_list(page_comments_ids)

        # 以下为不使用缓存
        # if args.type == 'a':
        #     #表示是对文章的评论
        #     #评论的哪篇文章
        #     article_id = args.source
        #     #查询数据库这篇文章的所有评论内容，多个
        #     # １文章id，２情况一：父级为空为文章评论，父级为评论的id为回复评论，３评论状态为审核通过，
        #     # ４找出来后通过时间戳或者id排序，由于自增，id排序即可，５查出所有all
        #     comments = Comment.query.filter(Comment.article_id == article_id,
        #                                     Comment.parent_id == None,
        #                                     Comment.status == Comment.STATUS.APPROVED).order_by(Comment.id.desc()).all()
        # else:
        #     #情况二：父级为评论的id为回复评论
        #     comment_id = args.source
        #     comments = Comment.query.filter(Comment.parent_id == comment_id,
        #                                     Comment.status == Comment.STATUS.APPROVED).order_by(Comment.id.desc()).all()
        # #初始化一些需要回复给前端的数据
        # page_comments = []
        # page_count=0
        # total_count = len(comments)   #评论总数，或者评论回复总数
        # page_last_comment = None
        #
        # for comment in comments:
        #     score = comment.ctime.timestamp() #评论创建时间的时间戳
        #     '''
        #     关于偏移量offset的查询逻辑！！！！！(有offset  or　没有offset) and 判断
        #     可能１》没有偏移量的判断：第一次获取时没有偏移量if offset is None and page_count <= limit
        #     可能２》有偏移量获取第２页时，偏移量为上次返回的最后一条评论的id，此处返回的是最后一条记录的创建时间的　时间戳供下次使用，
        #            所要查询的评论创建的时间戳肯定要早于（小于）偏移量
        #            if offset is not None and score < offset and page_count <= limit
        #     and的之后的判断相同，所以前面判断的部分用or分开，注意添加括号
        #     '''
        #
        #     if ((offset is not None and score < offset)or offset is None) and page_count <= limit:
        #         page_comments.append({
        #             'com_id': comment.id,
        #             'aut_id': comment.user.id,
        #             'aut_name': comment.user.name,
        #             'aut_photo': comment.user.profile_photo,
        #             'pubdate': comment.ctime.strftime('%Y-%m-%d %H:%M:%S'),
        #             'content': comment.content,
        #             'is_top': comment.is_top,
        #             'is_liking': False,
        #             'reply_count': 0
        #         })
        #         page_count += 1
        #         ''' 想要获取最后一条记录的创建时间的时间戳返回前端作为下次请求发来时的偏移量
        #             由于以上返回的字典中数据pubdate已经把时间戳变成字符串格式，
        #             此时添加一个临时变量，临时变量保存的内容一定为跳出for循环的最后一条，
        #             取用方便！！！！！　技巧
        #         '''
        #         page_last_comment = comment
        #
        # end_id = 0 # 最后一条评论的id, 前端用于判断是否剩余评论, 无值返回None
        # last_id = 0 # 本次请求最后一条评论的id, 作为下次请求的offset, 无值返回None
        # #以上两变量虽然写的是id，实际返回的是创建时间ctime的时间戳，此处容易误解
        # if len(comments) > 0:
        #     end_id = comments[-1].ctime.timestamp()
        #     last_id = page_last_comment.ctime.timestamp() if page_last_comment else None

        return {'total_count': total_count, 'end_id': end_id, 'last_id': last_id, 'results': page_comments}


#发布评论老师版本
class CommentResource2(Resource):
    method_decorators = {
        'post':[Loginrequired]
    }

    def post(self):
        """
        1.接收数据，验证数据
        2.数据入库
        3.返回相应
        :return:
        """
        # request.json
        # 1.接收数据，验证数据
        parser=reqparse.RequestParser()
        # target 是文章id
        parser.add_argument('target',location='json',required=True,type=int)
        parser.add_argument('content',location='json',required=True)
        parser.add_argument('art_id',location='json')

        args=parser.parse_args()

        target=args.get('target')
        content=args.get('content')
        art_id=args.get('art_id')
        user_id=g.user_id
        # 2.数据入库
        comment=Comment()
        comment.user_id=user_id
        comment.article_id=target
        comment.content=content
        if art_id:
            #回复评论
            comment.parent_id=target
            comment.article_id=art_id

            from cache.saticstic import CommentReplyCountStorage
            # value
            CommentReplyCountStorage.incr(target)

        db.session.add(comment)
        db.session.commit()
        # 3.返回相应
        return {
                   "com_id": comment.id,
                    "target": target
               },201

    """
    微博 是根据id来进行分页的

    1.我们是根据时间戳来进行分页数据获取的
    2.把所有的数据查询出来（简单的业务逻辑）
    3. 最后一条的时间戳 end_id (时间戳)
        当前分页的最后一条时间戳 last_id(时间戳)
    4. type  a表示文章评论 c表示回复评论
    """
    def get(self):
        """
        1.接收请求参数，验证请求参数
        2.获取请求参数
        3.根据type来查询数据（查询所有数据）
        4.初始化一些变量（计数器，分页数据，总数量）等
        5. 遍历
        6. 根据指定判断，获取指定的分页数据
            需要将对象转换为字典
        7. 返回相应
        :return:
        """
        # 1.接收请求参数，验证请求参数
        parser=reqparse.RequestParser()
        #添加验证参数
        """
        type(query)	    str	是	评论类型，a表示文章评论 c表示回复评论
        source(query)	int	是	文章id或者评论id
        offset(query)	int	否	获取评论数据的偏移量(时间戳)
        limit(query)	int	否	单页返回的记录条数，最大不超过50，默认为10
        """
        parser.add_argument('type',location='args',required=True)
        parser.add_argument('source',location='args',required=True,type=int)
        # offset 最好设置一下 验证类型
        parser.add_argument('offset',location='args',type=int)
        parser.add_argument('limit',location='args',type=inputs.int_range(DEFAULT_COMMENT_PER_PAGE_MIN,
                                                                          DEFAULT_COMMENT_PER_PAGE_MAX,
                                                                          'limit'))
        #验证
        args=parser.parse_args()
        # 2.获取请求参数
        type=args.get('type')
        source=args.get('source')
        offset=args.get('offset')
        limit=args.get('limit') if args.get('limit') is not None else DEFAULT_COMMENT_PER_PAGE_MIN

        if type == 'a':
            # 获取评论
            from cache.comment import ArticleCommentCache,CommentCache
            total_count,end_id,last_id,page_comments_ids=ArticleCommentCache(source).get_page(offset,limit)

            page_comments=[]
            for comment_id in page_comments_ids:
                c = CommentCache(comment_id).get()

                #判断当前的评论是否点赞
                from cache.user import UserCommentLikingCache
                is_liking=UserCommentLikingCache(g.user_id).get_comment_liking(comment_id)
                c['is_liking']=is_liking

                from cache.saticstic import CommentReplyCountStorage
                reply_count=CommentReplyCountStorage.get(comment_id)
                c['reply_count']=reply_count

                page_comments.append(c)

            # 7. 返回相应
            return {
                "total_count": total_count,
                "end_id": end_id,  # 最后一条评论的id, 前端用于判断是否剩余评论, 无值返回None
                "last_id": last_id,  # 本次请求最后一条评论的id, 作为下次请求的offset, 无值返回None
                "results": page_comments
            }
        else:
            # 获取评论回复
            """
            1.先把所有的评论回复（真对于某一个评论）查询出来
            2.初始化一些变量
              遍历的计数，end_id，last_id,total_count
            3.遍历所有的回复评论
            4.进行分页获取
            5.返回相应
            """
            from cache.comment import ArticleCommentReplyCache, CommentCache
            total_count, end_id, last_id, page_comments_ids = ArticleCommentReplyCache(source).get_page(offset, limit)

            page_comments = []
            for comment_id in page_comments_ids:
                c = CommentCache(comment_id).get()
                page_comments.append(c)

            # 5.返回相应
            return {'total_count':total_count,'end_id':end_id,'last_id':last_id,'results':page_comments}

# 给某个评论点赞
class CommentLikingResource(Resource):
    method_decorators = [Loginrequired]

    def post(self):
        '''
        接收数据，token验证用户是否登录,target要给哪个评论点赞
        验证数据
        查询数据库，不存在新增数据，存在修改标记位
        返回相应
        :return:
        '''
        # 接收验证数据
        parser = reqparse.RequestParser()
        parser.add_argument('target',location='json',type=int,required=True)
        args = parser.parse_args()
        target = args.target
        # 先查询数据库，是否存在 点赞信息
        cl = CommentLiking.query.filter(CommentLiking.comment_id == target).first()
        # 如果不存在则信息数据,新增数据
        if cl is None:
            cl = CommentLiking()
            cl.user_id = g.user_id
            cl.comment_id = target
            cl.is_deleted = False
            db.session.add(cl)
        else:
            # 如果存在，则修改标记位
            cl.is_deleted = False

        db.session.commit()
        #此方法不好用，不要使用try:新增，except:更新
        # try:
        #     comment_liking = CommentLiking(user_id=g.user_id,comment_id=target)
        #     db.session.add(comment_liking)
        #     db.session.commit()
        # # except IntegrityError:
        # except Exception:
        #     #　插入数据库提交失败，则新增
        #     db.session.rollback()
        #     CommentLiking.query.filter_by(user_id=g.user_id, comment_id=target, is_deleted=True).update({'is_deleted': False})
        #     db.session.commit()

        #给评论点赞之后，更改了状态，需要清除缓存
        from cache.user import UserCommentLikingCache
        UserCommentLikingCache(g.user_id).clear()

        return {'target':target},201